package ee.homework.fifth;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.Map.Entry;

public class Graph {

	private String[] files = new String[] { "G1.txt", "G2.txt", "G3.txt" };

	public static void main(String[] args) {
		Graph graph = new Graph();
		graph.start();
	}

	private void start() {
		for (int i = 0; i < files.length; i++) {
			int[][] matrix = readFileToMatrix("Data\\" + files[i]);
			System.out.println("Graph file: " + files[i]);
			System.out.println("Original graph");
			int sum = sumEdges(matrix);
			System.out.println("Edges: " + sum);
			int[][] newMatrix = createUndirectedGraph(matrix);
			System.out.println("Symmetrically connectected graph");
			sum = sumEdges(newMatrix);
			System.out.println("Edges: " + sum);
		}
	}

	private int[][] readFileToMatrix(String file) {
		int[][] matrix = null;
		try {
			BufferedReader reader = new BufferedReader(new FileReader(new File(
					file)));

			String line = null;
			int min = -1;
			int max = -1;
			List<String[]> list = new ArrayList<String[]>();
			while ((line = reader.readLine()) != null) {
				String[] splitLine = line.split(">");
				list.add(splitLine);
				int source = Integer.parseInt(splitLine[0].trim());
				int destination = Integer.parseInt(splitLine[1].trim());
				if (min == -1 || min > source)
					min = source;
				if (min > destination)
					min = destination;

				if (max == -1 || max < source)
					max = source;
				if (max < destination)
					max = destination;
			}
			int size = max - min + 1;
			matrix = new int[size][size];
			int row;
			int col;
			for (String[] strings : list) {
				row = Integer.parseInt(strings[0].trim());
				col = Integer.parseInt(strings[1].trim());
				matrix[row][col] = 1;
			}
		} catch (FileNotFoundException e) {
			System.out.println("File " + file + " does not exist");
		} catch (IOException e) {
			System.out.println("I/O exception");
			e.printStackTrace();
		}
		return matrix;
	}

	public Stack<Integer> breadthFirstSearch(int[][] matrix, int start) {
		Stack<Integer> queue = new Stack<Integer>();
		Stack<Integer> visited = new Stack<Integer>();

		queue.push(start);
		visited.push(start);
		while (!queue.isEmpty()) {
			int node = queue.pop();
			for (int i = 0; i < matrix.length; i++) {
				if (matrix[node][i] == 1 && !visited.contains(i)) {
					queue.push(i);
					visited.push(i);
				}
			}
		}
		return visited;
	}

	private void printMatrix(int[][] matrix) {
		for (int i = 0; i < matrix.length; i++) {
			System.out.println("Vertex: " + i);
			System.out.print("Adjacent vertices: ");
			for (int j = 0; j < matrix[0].length; j++) {
				if (matrix[i][j] == 1) {
					System.out.print(j + ", ");
				}
			}
			System.out.println();
		}
	}

	private int sum(int[][] matrix) {
		int sum = 0;
		for (int i = 0; i < matrix.length; i++) {
			for (int j = 0; j < matrix[0].length; j++) {
				if (j < i) {
					sum += matrix[i][j];
				}
			}
		}
		return sum;
	}

	private int sumEdges(int[][] matrix) {
		int sum = 0;
		for (int i = 0; i < matrix.length; i++) {
			for (int j = 0; j < matrix[0].length; j++) {
				sum += matrix[i][j];
			}
		}
		return sum;
	}

	private int[][] createUndirectedGraph(int[][] matrix) {
		int[][] tempMatrix = matrix;
		for (int i = 0; i < tempMatrix.length; i++) {
			for (int j = 0; j < tempMatrix[0].length; j++) {
				if (tempMatrix[i][j] == 1) {
					tempMatrix[j][i] = 1;
				}
			}
		}
		return tempMatrix;
	}

	private void printAdjList(Map<Node, List<Node>> adjList) {
		Set<Entry<Node, List<Node>>> eSet = adjList.entrySet();
		for (Entry<Node, List<Node>> entry : eSet) {
			Node vertex = entry.getKey();
			List<Node> adjVert = entry.getValue();
			System.out.println("Vertex: " + vertex);
			System.out.print("Adjacent vertices: ");
			for (Node vert : adjVert) {
				System.out.print(vert + ", ");
			}
			System.out.println();
		}
	}

	private Map<Node, List<Node>> readFileToList(String file) {
		Map<Node, List<Node>> adjList = new HashMap<Node, List<Node>>();
		try {
			BufferedReader reader = new BufferedReader(new FileReader(new File(
					file)));
			String line = null;
			Set<Entry<Node, List<Node>>> set;
			while ((line = reader.readLine()) != null) {
				set = adjList.entrySet();
				String[] splitLine = line.split(">");
				Node source = new Node(Integer.parseInt(splitLine[0].trim()));
				Node destination = new Node(Integer.parseInt(splitLine[1]
						.trim()));
				boolean src = false;
				for (Entry<Node, List<Node>> entry : set) {
					Node vertex = entry.getKey();
					if (vertex.getKey() == source.getKey()) {
						List<Node> adjVertices = entry.getValue();
						boolean dest = false;
						for (Node node : adjVertices) {
							if (node.getKey() == destination.getKey())
								dest = true;
						}
						if (!dest) {
							adjVertices.add(destination);
							adjList.put(vertex, adjVertices);
						}
						src = true;
					}
				}
				if (!src) {
					List<Node> adjVertices = new LinkedList<Node>();
					adjVertices.add(destination);
					adjList.put(source, adjVertices);
				}
			}
		} catch (FileNotFoundException e) {
			System.out.println("File " + file + " not found!");
			System.exit(1);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return adjList;
	}

	private Map<Node, List<Node>> createUndirectedGraph(
			Map<Node, List<Node>> adjList) {
		Map<Node, List<Node>> tempList = adjList;
		Set<Entry<Node, List<Node>>> set = tempList.entrySet();
		for (Entry<Node, List<Node>> entry : set) {
			Node vertex = entry.getKey();
			List<Node> vertices = entry.getValue();
			for (Node vert : vertices) {
				List<Node> adjVertices = tempList.get(vert);
				if (!adjVertices.contains(vertex)) {
					adjVertices.add(vertex);
					tempList.put(vert, adjVertices);
				}
			}
		}
		return tempList;
	}

	private int sumEdges(Map<Node, List<Node>> adjList) {
		Set<Entry<Node, List<Node>>> set = adjList.entrySet();
		int sum = 0;
		for (Entry<Node, List<Node>> entry : set) {
			sum += entry.getValue().size();
		}
		return sum;
	}
}
